package open.panxiong.shared.http

import android.util.Log
import fi.iki.elonen.NanoHTTPD
import open.panxiong.shared.http.annotation.NanohttpdApi
import open.panxiong.shared.http.config.ConstConfig
import open.panxiong.shared.http.controller.DefaultController
import open.panxiong.shared.http.controller.DownloadController
import open.panxiong.shared.http.controller.FileController
import open.panxiong.shared.http.controller.ImageController
import open.panxiong.shared.http.controller.TextController
import open.panxiong.shared.http.controller.VideoController
import open.panxiong.shared.service.NanohttpdService
import java.io.InputStream
import java.lang.reflect.Method


class NanohttpdHttp(port: Int, private var service: NanohttpdService) : NanoHTTPD(port) {
    companion object {
        const val WWW_DIR = "www"
    }

    // 注册控制器
    private val controllerList = listOf(
        DefaultController::class.java,
        FileController::class.java,
        VideoController::class.java,
        ImageController::class.java,
        TextController::class.java,
    )

    private val controllerMapper = mutableMapOf<String, ControllerModel>()

    init {
        for (clazz in controllerList) {
            for (method in clazz.declaredMethods) {
                val instance = clazz.getDeclaredConstructor().newInstance()
                val annotation = method.getAnnotation(NanohttpdApi::class.java)
                if (annotation?.value != null) {
                    method.isAccessible = true
                    controllerMapper[annotation.value] = ControllerModel(instance, method)
                }
            }
        }
    }

    override fun serve(session: IHTTPSession): Response {
        val response = distribution(session) ?: handlerDefault(session)
        response.addHeader("Access-Control-Allow-Origin", "*");
        response.addHeader("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE");
        response.addHeader("Access-Control-Allow-Headers", "Content-Type");
        return response
    }

    // 派发request，要求controller对象的方法必须按规定的格式命名
    private fun distribution(session: IHTTPSession): Response? {
        try {
            var uri = session.uri
            if (uri.contains("?")) {
                uri = uri.split("?")[0]
            }
            if (uri.contains("#")) {
                uri = uri.split("#")[0]
            }
            uri = uri.trim()
            val mapper = controllerMapper[uri]
            if (mapper != null) {
                return mapper.method.invoke(mapper.obj, service, session) as Response
            }
            if (uri.startsWith(ConstConfig.API_PREFIX_DOWNLOAD)) {
                return DownloadController.download(service, session)
            }
        } catch (e: Exception) {
            Log.e("NanohttpdHttp", "distribution", e)
        }
        return null
    }

    // 处理默认访问
    private fun handlerDefault(session: IHTTPSession): Response {
        var uri = session.uri
        if (uri.isNullOrEmpty() || uri == "/") {
            uri = "/index.html"
        }

        fun getAssetsFile(path: String): InputStream? {
            return try {
                service.assets.open(WWW_DIR + path)
            } catch (_: Exception) {
                null
            }
        }

        fun getFileName(path: String): String {
            val strings = path.split("/")
            if (strings.isEmpty()) {
                return "index.html"
            }
            return strings[strings.size - 1]
        }

        val data = getAssetsFile(uri)
        return if (data != null) {
            newChunkedResponse(Response.Status.OK, getMimeTypeForFile(getFileName(uri)), data)
        } else {
            newFixedLengthResponse(Response.Status.NOT_FOUND, "text/plain", "404 NOT FOUND")
        }
    }
}

data class ControllerModel(
    var obj: Any,
    var method: Method
)